package com.runa.monitor.platinterface.netservice.equipment;

import com.runa.monitor.comm.dto.Archive;
import com.runa.monitor.comm.dto.Node;
import com.runa.monitor.comm.dto.newComm.ValveVO;
import com.runa.monitor.platinterface.backwork.function.TaskFunction;
import com.runa.monitor.platinterface.backwork.impl.RccTaskFunction;
import com.runa.monitor.platinterface.mqtt.MqttBaseController;
import com.runa.monitor.platinterface.netservice.connect.commstatus.CommStatus;
import com.runa.protocol.dto.DtuHDRequestData;
import com.runa.protocol.util.ByteUtil;
import com.runa.protocol.util.UtilTime;
import com.runa.rccprotocol.dto.ConcentratorRequestData;
import com.runa.rccprotocol.dto.ConcentratorRequestDataProxy;
import com.runa.rccprotocol.dto.ConcentratorResponseData;
import com.runa.rccprotocol.dto.equdata.EquData;
import com.runa.rccprotocol.dto.param.ExtendParam;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.dto.runa.RunaDeviceRequestData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
public class RunaLDtuDriver extends NetEqu<String> {

    private final List<Node> buildValves;

    private static final Map<String, ConcentratorRequestData> valveRequest = new ConcurrentHashMap<>();

    private final Map<Integer, String> valveIdxSerial = new HashMap<>();

    public RunaLDtuDriver(String serial, Integer timeout, TaskFunction function, List<Node> buildValves) {
        super(serial, timeout);
        this.autoUpFunction = function;
        this.buildValves = buildValves;
    }

    public void readBuildValves() {
        log.info("LDTU:{} 抄读阀门", serial());
        for (Node node : buildValves) {
            int salve = Integer.parseInt(node.getSerial());
            valveIdxSerial.put(salve, node.getSerial());
            RunaDeviceRequestData requestData = new RunaDeviceRequestData();
            requestData.readBuildValve(salve);
            ConcentratorRequestDataProxy dataProxy = new ConcentratorRequestDataProxy(serial(), new DtuHDRequestData(serial(), requestData));
            dataProxy.setRemain(Collections.singletonList(node));
            sendRequest(dataProxy, this.autoUpFunction);
        }
    }

    public void sentBuildValves() {
        log.info("LDTU:{} 下发缓存指令", serial());
        for (Node node : buildValves) {
            ConcentratorRequestData requestData = valveRequest.remove(serial()+node.getSerial());
            if (requestData != null) {
                sendRequest(requestData, new RccTaskFunction.EmptyTask());
            }
        }
    }

    @SneakyThrows
    public void sentDateTime() {
        log.info("LDTU:{} 下发校时", serial());
        RunaDeviceRequestData requestData = new RunaDeviceRequestData();
        requestData.setData(("rtc:"+UtilTime.getCurrentTime("yyyyMMddHHmmss")+"\r\n").getBytes());
        sendRequest(requestData, new RccTaskFunction.EmptyTask());
    }

    @Override
    public void readNodeEqu(List<Node> nodes, TaskFunction function, EquData.EquDataType type) {
        switch (type) {
            case PUBLIC_UNIT:
                if (heartStop()) {
                    function.doApply(CommStatus.OffLine, null);
                } else {
                    for (Node node : nodes) {
                        int salve = Integer.parseInt(node.getSerial());
                        valveIdxSerial.put(salve, node.getSerial());
                        RunaDeviceRequestData requestData = new RunaDeviceRequestData(serial());
                        requestData.readBuildValve(salve);
                        ConcentratorRequestDataProxy dataProxy = new ConcentratorRequestDataProxy(serial(), requestData);
                        sendRequest(dataProxy, function);
                    }
                }
                break;
        }
    }

    @Override
    public void setNodeEquArchive(List<Archive> archives, TaskFunction function) {

    }

    @Override
    public void clearNodeEquArchive(TaskFunction function) {

    }

    @Override
    public void valveOnOffControl(List<Node> nodeList, boolean ifLock, Integer opening, TaskFunction function) {

    }

    @Override
    public void readNodeRecord(List<Integer> indexes, TaskFunction function) {

    }

    @Override
    public void sentPublicUnitRecord(List<Node> nodeList, Integer model, Map param, TaskFunction function) {
        for (Node unit : nodeList) {
            if (unit != null) {
                switch (model) {
                    case 1:
                        RunaDeviceRequestData requestData = new RunaDeviceRequestData();
                        requestData.setBuildValveOpen(Integer.parseInt(unit.getSerial()), (int) Float.parseFloat(param.get("targetValue").toString()));
                        DtuHDRequestData hdRequestData = new DtuHDRequestData(serial(), requestData);
                        ConcentratorRequestDataProxy dataProxy = new ConcentratorRequestDataProxy(serial(), hdRequestData);
                        if (heartStop()) {
                            valveRequest.put(serial()+unit.getSerial(), dataProxy);
                            function.setStatus(unit);
                            function.doApply(CommStatus.OK, new RunaConcenAffirmDeny(true));
                        } else {
                            sendRequest(dataProxy, function);
                        }
                        break;
                    case 2:
                    case 3:
                    case 4:
                        break;
                    default:
                }
            }
        }
    }

    @Override
    public void sentPublicUnitModel(List<Node> nodeList, boolean model, TaskFunction function) {

    }

    @Override
    public void sentExtendParam(ExtendParam param, TaskFunction function) {

    }

    @Override
    public void readPublicUnitRecord(Node valve, Integer model, TaskFunction function) {

    }

    @Override
    public void readPublicUnitAndMeter(Node valve, Node meter, TaskFunction function) {

    }

    @Override
    protected void writeOutput(ConcentratorRequestData requestData) {
        log.info("LDTU {} 下发: {}", serial(), ByteUtil.byteToHexString(requestData.getData()));
        MqttBaseController.getConnector().sendMessage("/RU-LDTU-01/"+serial()+"/down", requestData.getData());
    }

    @Override
    public void receive(ConcentratorResponseData responseData) {
        if (responseData.getData() instanceof List) {
            List list = (List) responseData.getData();
            if (!list.isEmpty() && list.get(0) instanceof ValveVO) {
                ValveVO valveVO = (ValveVO) list.get(0);
                valveVO.setValveSerial(valveIdxSerial.get(valveVO.getIndex()));
            }
        }
        super.receive(responseData);
    }

    @Override
    public boolean online() {
        return true;
    }

    private long second;

    @Override
    public void heartbeatUpdate() {
        this.second = LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8"));
    }

    @Override
    public boolean heartStop() {
        return LocalDateTime.now().toEpochSecond(ZoneOffset.of("+8")) - this.second > 15;
    }
}
